﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using FileWatcher;
using System.Diagnostics.Eventing.Reader;

namespace FileWatcherDemo
{
	public partial class Form1Ex : Form
	{
		WatcherEx fileWatcher = null;

		public Form1Ex()
		{
			InitializeComponent();

            this.textBoxFolderToWatch.Text = @"C:\Temp\Exclusivos";
			this.buttonStart.Enabled = true;
			this.buttonStop.Enabled = false;
		}

        #region MyRegion
        //public static EventUnit DisplayEventAndLogInformation(string fileToSearch, DateTime actionTime)
        //{
        //    StringBuilder sb = new StringBuilder();
        //    const string queryString = @"<QueryList><Query Id=""0"" Path=""Security""><Select Path=""Security"">*</Select></Query></QueryList>";
        //    EventLogQuery eventsQuery = new EventLogQuery("Security", PathType.LogName, queryString);
        //    eventsQuery.ReverseDirection = true;
        //    EventLogReader logReader = new EventLogReader(eventsQuery);
        //    EventUnit e = new EventUnit();
        //    bool isStop = false;
        //    for (EventRecord eventInstance = logReader.ReadEvent(); null != eventInstance; eventInstance = logReader.ReadEvent())
        //    {
        //        foreach (var VARIABLE in eventInstance.Properties)
        //            if (VARIABLE.Value.ToString().ToLower().Contains(fileToSearch.ToLower()) && actionTime.ToString("d/M/yyyy HH:mm:ss") == eventInstance.TimeCreated.Value.ToString("d/M/yyyy HH:mm:ss"))
        //            {
        //                foreach (var VARIABLE2 in eventInstance.Properties) sb.AppendLine(VARIABLE2.Value.ToString());
        //                e.Message = sb.ToString();
        //                e.User = (eventInstance.Properties.Count > 1) ? eventInstance.Properties[1].Value.ToString() : "n/a";
        //                e.File = fileToSearch;
        //                isStop = true;
        //                break;
        //            }
        //        if (isStop) break;
        //        try
        //        {
        //            //    Console.WriteLine("Description: {0}", eventInstance.FormatDescription());
        //        }
        //        catch (Exception e2)
        //        {
        //        }
        //    }
        //    return e;
        //}
        #endregion

        #region MyRegion
        private string GetSpecificFileProperties(string file, params int[] indexes)
        {
            string fileName = Path.GetFileName(file);
            string folderName = Path.GetDirectoryName(file);
            Shell32.Shell shell = new Shell32.Shell();
            Shell32.Folder objFolder;
            objFolder = shell.NameSpace(folderName);
            StringBuilder sb = new StringBuilder();

            foreach (Shell32.FolderItem2 item in objFolder.Items())
            {
                if (fileName == item.Name)
                {
                    for (int i = 0; i < indexes.Length; i++)
                    {
                        sb.Append(objFolder.GetDetailsOf(item, indexes[i]) + ",");
                    }

                    break;
                }
            }

            string result = sb.ToString().Trim();
            //Protection for no results causing an exception on the `SubString` method
            if (result.Length == 0)
            {
                return string.Empty;
            }
            return result.Substring(0, result.Length - 1);
        }
        #endregion
        

		#region Helper Methods
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Toggles the Watcher event handlers on/off
		/// </summary>
		/// <param name="add"></param>
		private void ManageEventHandlers(bool add)
		{
			// For the purposes of this demo, I funneled all of the change events into 
			// one handler to keep the codebase smaller. You could certainly have an 
			// individual handler for each type of change event if you desire.
			if (fileWatcher != null)
			{
				if (add)
				{
					fileWatcher.EventChangedAttribute     += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedCreationTime  += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedDirectoryName += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedFileName      += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedLastAccess    += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedLastWrite     += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedSecurity      += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedSize          += new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventCreated              += new WatcherExEventHandler(fileWatcher_EventCreated);
					fileWatcher.EventDeleted              += new WatcherExEventHandler(fileWatcher_EventDeleted);
					fileWatcher.EventDisposed             += new WatcherExEventHandler(fileWatcher_EventDisposed);
					fileWatcher.EventError                += new WatcherExEventHandler(fileWatcher_EventError);
					fileWatcher.EventRenamed              += new WatcherExEventHandler(fileWatcher_EventRenamed);
					fileWatcher.EventPathAvailability     += new WatcherExEventHandler(fileWatcher_EventPathAvailability);
				}
				else
				{
					fileWatcher.EventChangedAttribute     -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedCreationTime  -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedDirectoryName -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedFileName      -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedLastAccess    -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedLastWrite     -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedSecurity      -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventChangedSize          -= new WatcherExEventHandler(fileWatcher_EventChanged);
					fileWatcher.EventCreated              -= new WatcherExEventHandler(fileWatcher_EventCreated);
					fileWatcher.EventDeleted              -= new WatcherExEventHandler(fileWatcher_EventDeleted);
					fileWatcher.EventDisposed             -= new WatcherExEventHandler(fileWatcher_EventDisposed);
					fileWatcher.EventError                -= new WatcherExEventHandler(fileWatcher_EventError);
					fileWatcher.EventRenamed              -= new WatcherExEventHandler(fileWatcher_EventRenamed);
					fileWatcher.EventPathAvailability     += new WatcherExEventHandler(fileWatcher_EventPathAvailability);
				}
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Initializes the Watcher object. In the interest of providing a complete 
		/// demonstration, all change events are monitored. This will unlikely be a 
		/// real-world requirement in most cases.
		/// </summary>
		private bool InitWatcher()
		{
			bool result = false;
			if (Directory.Exists(this.textBoxFolderToWatch.Text) || File.Exists(this.textBoxFolderToWatch.Text))
			{
				WatcherInfo info = new WatcherInfo();
				info.ChangesFilters = NotifyFilters.Attributes    | 
				                      NotifyFilters.CreationTime  | 
				                      NotifyFilters.DirectoryName | 
				                      NotifyFilters.FileName      | 
				                      NotifyFilters.LastAccess    | 
				                      NotifyFilters.LastWrite     | 
				                      NotifyFilters.Security      | 
				                      NotifyFilters.Size;

				info.IncludeSubFolders = this.checkBoxIncludeSubfolders.Checked;
				info.WatchesFilters    = WatcherChangeTypes.All;
				info.WatchForDisposed  = true;
				info.WatchForError     = false;
				info.WatchPath         = this.textBoxFolderToWatch.Text;
				info.BufferKBytes      = 8;
				info.MonitorPathInterval = 250;
				fileWatcher            = new WatcherEx(info);
				ManageEventHandlers(true);
				result = true;
			}
			else
			{
				MessageBox.Show("The folder (or file) specified does not exist.\nPlease specify a valid folder or filename.");
			}
			return result;
		}
		#endregion Helper Methods

		#region ListView Update Delegate Methods and Definitions 
		private delegate void DelegateCreateListViewItem(string eventName, string filterName, string fileName);

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Common ListViewItem creation for all events.  This method checks to see if 
		/// invoke is required, and makes the appropriate call to the 
		/// InvokedCreateListViewItem() method.
		/// </summary>
		/// <param name="eventName"></param>
		/// <param name="filterName"></param>
		/// <param name="fileName"></param>
		void CreateListViewItem(string eventName, string filterName, string fileName)
		{
			if (this.listView1.InvokeRequired)
			{
		        DelegateCreateListViewItem method = new DelegateCreateListViewItem(InvokedCreateListViewItem);
				Invoke(method, new object[3]{eventName, filterName, fileName} );
			}
			else
			{
				InvokedCreateListViewItem(eventName, filterName, fileName);
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// The method actually used to update the listview. 
		/// </summary>
		/// <param name="eventName"></param>
		/// <param name="filterName"></param>
		/// <param name="fileName"></param>
		private void InvokedCreateListViewItem(string eventName, string filterName, string fileName)
		{
			ListViewItem lvi = new ListViewItem();
			lvi.Text = DateTime.Now.ToString("HH:mm:ss");
			lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, eventName)); 
			lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, filterName)); 
			lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, fileName));
			//this.listView1.BeginUpdate();
			this.listView1.Items.Add(lvi);
			this.listView1.EnsureVisible(this.listView1.Items.Count - 1);
			//this.listView1.EndUpdate();
		}
		#endregion ListView Update Delegate Methods and Definitions 

		#region Watcher Events
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object detects a file rename event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventRenamed(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Renamed", "N/A", (e.Arguments == null) ? "Null argument object": ((RenamedEventArgs)(e.Arguments)).FullPath);
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object detects an error event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventError(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Error", "N/A", (e.Arguments == null) ? "Null argument object": ((EventArgs)(e.Arguments)).ToString());
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object disposes one of the internal FileSystemWatcher 
		/// objects.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventDisposed(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Disposed", "N/A", (e.Arguments == null) ? "Null argument object": ((EventArgs)(e.Arguments)).ToString());
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object detects a file deleted event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventDeleted(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Deleted", "N/A", (e.Arguments == null) ? "Null argument object": ((FileSystemEventArgs)(e.Arguments)).FullPath);
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object detects a file created event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventCreated(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Created", "N/A", (e.Arguments == null) ? "Null argument object": ((FileSystemEventArgs)(e.Arguments)).FullPath);
            //MessageBox.Show("Inicio");
            DirectoryInfo d = new DirectoryInfo(this.textBoxFolderToWatch.Text);
            FileInfo[] infos = d.GetFiles();

            foreach (FileInfo f in infos)
            {
                if (f.Name.Length <= 12)
                {
                    var oldName = f.Name;
                    var extension = Path.GetExtension(f.FullName);
                    var newName = string.Empty;
                    var aStringBuilder = new StringBuilder(oldName);
                    aStringBuilder.Remove(8, f.Name.Count() - 8);
                    aStringBuilder.Insert(8, "SPK" + extension);
                    newName = aStringBuilder.ToString();
                    var newFullname = f.DirectoryName + '\\' + newName;

                    var bStringBuilder = new StringBuilder(f.Name);
                    bStringBuilder.Insert(0, "OLD");
                    var repName = bStringBuilder.ToString();


                    if (File.Exists(newFullname))
                    {
                        File.Delete(newFullname);
                        //MessageBox.Show("Existe");
                        //File.Move(f.FullName, f.FullName.ToString().Replace(newName, repName));
                    }
                    File.Move(f.FullName, f.FullName.ToString().Replace(f.Name, newName));


                    string Type = GetSpecificFileProperties(f.FullName, 2);
                    string ObjectKind = GetSpecificFileProperties(newFullname, 11);
                    DateTime CreatedDate = Convert.ToDateTime(GetSpecificFileProperties(newFullname, 4));
                    DateTime LastModifiedDate = Convert.ToDateTime(GetSpecificFileProperties(newFullname, 3));
                    DateTime LastAccessDate = Convert.ToDateTime(GetSpecificFileProperties(newFullname, 5));
                    string LastUser = GetSpecificFileProperties(newFullname, 10);
                    string ComputerName = GetSpecificFileProperties(newFullname, 53);
                    string FileSize = GetSpecificFileProperties(newFullname, 1);
                }
                
            }
           
            d.Refresh();
            MessageBox.Show("FIM");
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the Watcher object detects a folder/file change event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventChanged(object sender, WatcherExEventArgs e)
		{
			CreateListViewItem("Change", e.Filter.ToString(), (e.Arguments == null) ? "Null argument object": ((FileSystemEventArgs)(e.Arguments)).FullPath);
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the availability of the folder has changed.  If it becomes 
		/// "disconnected", the internal watchers are disabled. When it becomes connected 
		/// again, the internal watchers are restored.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void fileWatcher_EventPathAvailability(object sender, WatcherExEventArgs e)
		{
			string eventName  = "Availability";
			string filterName = "N/A";
			string status   = "";
			if (e.Arguments == null) 
			{
				status = "Null argument object";
			}
			else
			{
				status = (((PathAvailablitiyEventArgs)(e.Arguments)).PathIsAvailable) ? "Connected" 
				                                                                      : "Disconnected";
			}
		    CreateListViewItem(eventName, filterName, status);
		}

		#endregion Watcher Events

		#region Form Events
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the form is closing. Disposes the Watcher object
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Form1Ex_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (fileWatcher != null)
			{
				ManageEventHandlers(false);
				fileWatcher.Dispose();
				fileWatcher = null;
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Start button
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonStart_Click(object sender, EventArgs e)
		{
			if (fileWatcher != null)
			{
				fileWatcher.Dispose();
				fileWatcher = null;
			}
			if (InitWatcher())
			{
				this.fileWatcher.Start();
				this.buttonStart.Enabled = false;
				this.buttonStop.Enabled = true;
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Stop button
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonStop_Click(object sender, EventArgs e)
		{
			if (fileWatcher != null)
			{
				ManageEventHandlers(false);
				this.fileWatcher.Stop();
				this.buttonStart.Enabled = true;
				this.buttonStop.Enabled = false;
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Done button
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonDone_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Browse button.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonBrowse_Click(object sender, EventArgs e)
		{
			string appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 
			if (string.IsNullOrEmpty(appDataFolder))
			{
				MessageBox.Show("Could not determine the name of the ApplicationData folder\non this machine. Terminating browse attempt.");
				return;
			}
			if (string.IsNullOrEmpty(this.textBoxFolderToWatch.Text))
			{
				this.textBoxFolderToWatch.Text = appDataFolder; 
			}
			// determine the foler from which we start browsing
			string startingDir = this.textBoxFolderToWatch.Text;
			// if the specified folder doesn't exist
			if (!Directory.Exists(startingDir))
			{
				MessageBox.Show("Specified folder does not exist. Starting with\nthe ApplicationData folder instead.");
				// set our starting folder to the user's application data folder
				startingDir = appDataFolder;
			}

			FolderBrowserDialog dlg = new FolderBrowserDialog();
			dlg.SelectedPath = startingDir;
			DialogResult result = dlg.ShowDialog();
			if (result == DialogResult.OK)
			{
				if (!string.IsNullOrEmpty(dlg.SelectedPath))
				{
					this.textBoxFolderToWatch.Text = dlg.SelectedPath;
				}
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Clear List button
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonClearList_Click(object sender, EventArgs e)
		{
			this.listView1.Items.Clear();
		}
		#endregion Form Events

	}
}
